/**
 * @file main_ts.c
 *
 * @author yhuan416<yhuan416@foxmail.com>
 * @date 2025-10-03
 *
 * @brief 线程安全 mobjbuf 演示程序
 *          展示如何使用线程安全接口和外部锁函数
 */

#include "mobjbuf_ts.h"
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>

// 全局指针数组，用于存储分配的内存
void *g_ptr_group[20] = {NULL};

// 互斥锁用于演示外部锁函数
static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;

/**
 * @brief 外部临界区保护函数（使用 pthread 互斥锁）
 *
 * @param userdata 用户数据指针
 * @param is_lock true: 加锁, false: 解锁
 */
static void pthread_lock_fn(void *userdata, bool is_lock)
{
    (void)userdata; // 未使用

    if (is_lock)
    {
        pthread_mutex_lock(&g_mutex);
        printf("[LOCK] Thread %lu acquired lock\n", (unsigned long)pthread_self());
    }
    else
    {
        printf("[UNLOCK] Thread %lu released lock\n", (unsigned long)pthread_self());
        pthread_mutex_unlock(&g_mutex);
    }
}

/**
 * @brief 淘汰回调函数示例
 *
 * @param objbuf 内存池对象
 * @param require_size 需要释放的内存大小
 * @param userdata 用户数据指针
 *
 * @return 淘汰状态
 */
static int my_evict_callback(mobjbuf_t *objbuf, size_t require_size, void *userdata)
{
    (void)require_size;
    (void)userdata;

    printf("[EVICT] Thread %lu: Space low, evicting data...\n", (unsigned long)pthread_self());

    // 从全局指针数组中找一个已分配的内存进行释放
    for (int i = 0; i < 20; i++)
    {
        if (g_ptr_group[i] != NULL)
        {
            printf("[EVICT] Thread %lu: Evicted memory at[%d]: %p\n",
                   (unsigned long)pthread_self(), i, g_ptr_group[i]);
            mobjbuf_free(objbuf, g_ptr_group[i]);
            g_ptr_group[i] = NULL;
            return MOBJBUF_EVICT_DONE; // 返回 MOBJBUF_EVICT_DONE 表示已释放空间
        }
    }

    printf("[EVICT] Thread %lu: No memory to evict\n", (unsigned long)pthread_self());
    return MOBJBUF_EVICT_NONE; // 返回 MOBJBUF_EVICT_NONE 表示未释放空间
}

/**
 * @brief 工作线程参数结构
 */
typedef struct
{
    mobjbuf_ts_t *ts_objbuf; // 线程安全内存池指针
    int thread_id;           // 线程ID
} worker_thread_arg_t;

/**
 * @brief 工作线程函数
 *
 * @param arg 线程参数（worker_thread_arg_t 指针）
 *
 * @return NULL
 */
static void *worker_thread(void *arg)
{
    worker_thread_arg_t *thread_arg = (worker_thread_arg_t *)arg;
    mobjbuf_ts_t *ts_objbuf = thread_arg->ts_objbuf;
    int thread_id = thread_arg->thread_id;
    int alloc_size = 50 + (thread_id * 10);
    int counts = 5;

    printf("[THREAD %d] Started, thread_id: %lu\n", thread_id, (unsigned long)pthread_self());

    while (counts--)
    {
        // 随机选择一个索引
        int index = rand() % 20;

        // 如果该位置已有内存，先释放
        if (g_ptr_group[index] != NULL)
        {
            printf("[THREAD %d] Freeing existing memory at[%d]: %p\n",
                   thread_id, index, g_ptr_group[index]);
            mobjbuf_ts_free(ts_objbuf, g_ptr_group[index]);
            g_ptr_group[index] = NULL;
        }

        // 分配新内存
        printf("[THREAD %d] Allocating %d bytes at index[%d]\n", thread_id, alloc_size, index);
        g_ptr_group[index] = mobjbuf_ts_alloc(ts_objbuf, alloc_size, my_evict_callback, NULL);

        if (g_ptr_group[index] == NULL)
        {
            printf("[THREAD %d] Allocation failed!\n", thread_id);
        }
        else
        {
            printf("[THREAD %d] Allocated %d bytes at %p\n", thread_id, alloc_size, g_ptr_group[index]);

            // 模拟使用内存
            memset(g_ptr_group[index], thread_id, alloc_size);
        }

        // 随机增加分配大小
        alloc_size += rand() % 50;

        // 随机休眠一段时间
        usleep(100000 + (rand() % 200000)); // 100-300ms
    }

    printf("[THREAD %d] Finished\n", thread_id);
    return NULL;
}

/**
 * @brief 主函数
 *
 * @return 程序退出码
 */
int main()
{
    const int NUM_THREADS = 4;
    pthread_t threads[NUM_THREADS];
    uint8_t buffer[4096]; // 4KB 预分配缓冲区
    mobjbuf_ts_t ts_mem_pool;

    printf("=========================================\n");
    printf("Thread-Safe mobjbuf Demo\n");
    printf("Buffer size: %zu bytes\n", sizeof(buffer));
    printf("Number of threads: %d\n", NUM_THREADS);
    printf("=========================================\n\n");

    // 初始化随机数种子
    srand((unsigned int)time(NULL));

    // 初始化线程安全内存池
    printf("[MAIN] Initializing thread-safe memory pool...\n");
    if (mobjbuf_ts_init(&ts_mem_pool, buffer, sizeof(buffer), pthread_lock_fn, NULL) != 0)
    {
        printf("[MAIN] Failed to initialize memory pool!\n");
        exit(1);
    }
    printf("[MAIN] Memory pool initialized successfully\n\n");

    // 打印初始状态
    printf("[MAIN] Initial memory pool status:\n");
    mobjbuf_ts_dump(&ts_mem_pool);

    // 创建多个工作线程
    printf("[MAIN] Creating %d worker threads...\n\n", NUM_THREADS);
    worker_thread_arg_t thread_args[NUM_THREADS];
    for (int i = 0; i < NUM_THREADS; i++)
    {
        thread_args[i].ts_objbuf = &ts_mem_pool;
        thread_args[i].thread_id = i + 1;

        if (pthread_create(&threads[i], NULL, worker_thread, &thread_args[i]) != 0)
        {
            printf("[MAIN] Failed to create thread %d\n", i + 1);
            exit(1);
        }
    }

    // 等待所有线程完成
    printf("[MAIN] Waiting for all threads to complete...\n\n");
    for (int i = 0; i < NUM_THREADS; i++)
    {
        pthread_join(threads[i], NULL);
    }

    // 打印最终状态
    printf("\n[MAIN] Final memory pool status:\n");
    mobjbuf_ts_dump(&ts_mem_pool);

    // 清理所有分配的内存
    printf("[MAIN] Cleaning up all allocated memory...\n");
    for (int i = 0; i < 20; i++)
    {
        if (g_ptr_group[i] != NULL)
        {
            mobjbuf_ts_free(&ts_mem_pool, g_ptr_group[i]);
            g_ptr_group[i] = NULL;
        }
    }

    // 打印清理后的状态
    printf("[MAIN] Memory pool status after cleanup:\n");
    mobjbuf_ts_dump(&ts_mem_pool);

    // 销毁互斥锁
    pthread_mutex_destroy(&g_mutex);

    printf("=========================================\n");
    printf("Demo completed successfully!\n");
    printf("=========================================\n");

    return 0;
}